/*
 * @Desc: 南自设备103协议客户端，实现读取保护装置定值模板，下传用户输入的定值到保护装置
 *
 * */

#include "NZ/NZ103Client.h"
#include "ui_NZ103Client.h"
#include <QByteArray>
#include <QDebug>
#include <QThread>

NZ103Client::NZ103Client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::NZ103Client)
{
    ui->setupUi(this);
    m_server = new NZConnection;
    ui->lineEditCpuAddr->setText(ASDU_CPU_ADDR);
    ui->lineEditLocalPort->setText("1048");     // 主站tcp 服务端端口
    ui->lineEditTargetPort->setText("1032");     // 保护设备服务端口号
    QStringList localIP = m_server->getLocalHostIPList();
    ui->comboBoxLocalAddr->addItem("127.0.0.1");
    ui->comboBoxLocalAddr->addItems(localIP);

    ui->pushButtonStopTcpServer->setEnabled(false);
    ui->pushButtonSendTcpMsg->setEnabled(false);
    ui->pushButtonSendCMD->setEnabled(false);

    ui->pushButtonReadAll->setEnabled(false);
    ui->pushButtonSendUdpMsg->setEnabled(false);

     m_timerGetParseResult.setSingleShot(true);     // 单次延迟几秒后获取到底层的结果

    // 接收 udp 消息
    connect(m_server,&NZConnection::sig_readyRadUdp, this, &NZ103Client::slot_UdpSocketRecv);

    //tcp
    m_panelBill = new PanelBill;
    m_parser = new NZParser;

    // 将parser解析完后的结果传给界面
    connect(this, &NZ103Client::signal_parseFinished, m_panelBill, &PanelBill::slot_recvParserResult);
    //connect(m_parser, &NZParser::signal_parseFinished, m_panelBill, &PanelBill::slot_recvParserResult);

    connect(ui->pushButtonStartTcpServer, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonStartTcpServer_clicked);
    connect(ui->pushButtonStopTcpServer, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonStopTcpServer_clicked);
    connect(ui->pushButtonSendTcpMsg, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonSendTcpMsg_clicked);
    connect(ui->pushButtonSendUdpMsg, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonSendUdpMsg_clicked);
    connect(ui->pushButtonShowTable, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonShowTable_clicked);
    connect(ui->pushButtonGetModifiedValues, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonGetModifiedValues_clicked);
    connect(ui->pushButtonClearRecv, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonClearTcpRecv_clicked);
    connect(ui->pushButtonReadAll, &QPushButton::clicked, this, &NZ103Client::slot_pushButtonReadAll_clicked);
    connect(ui->pushButtonSendCMD, &QPushButton::clicked, this , &NZ103Client::slot_pushButtonSendCMD_clicked);
    connect(m_server, &NZConnection::sig_sendTcpMsg, this, &NZ103Client::slot_updateUiAsSend);
    connect(m_server, &NZConnection::sig_sendUDPMsg, this, &NZ103Client::slot_updateUiAsSend);

    // 收到 tcp 报文
    connect(m_server, &NZConnection::sig_readyReadTcp, this, &NZ103Client::slot_readTcpData);

    connect(&m_readTitleTimer, &QTimer::timeout, this, &NZ103Client::slot_readAllTitles);

    connect(this, &NZ103Client::sig_getTitleInfoFinished, this, &NZ103Client::slot_setCanReadBillInfo);
    //connect(m_parser, &NZParser::sig_getTitleInfoFinished, this, &NZ103Client::slot_setCanReadBillInfo);

   connect(this, &NZ103Client::sig_getBillAreaFinished, this, &NZ103Client::slot_selectBillArea);  // 定值区号读取成功，下一步自动选择当前定值区号
   // connect(m_parser, &NZParser::sig_getBillAreaFinished, this, &NZ103Client::slot_selectBillArea);

   connect(this, &NZ103Client::sig_sureBillAreaFinished, this, &NZ103Client::slot_readBillGroupInfo);
    // 子线程解析报文
    connect(&m_timerGetParseResult, &QTimer::timeout, this, &NZ103Client::slot_getBillInfo);    // 在用户点击读取后定时获取解析结果

//    m_parserThread = new QThread;
//    m_parser->moveToThread(m_parserThread);
//    m_parserThread->start();
//    connect(this, &NZ103Client::sig_newsRecv, m_parser, &NZParser::slot_parseBillInfo);
}

NZ103Client::~NZ103Client()
{
    delete ui;
    delete m_server;
    delete m_constructer;       // 报文构造工具
    delete  m_parser;             // 报文对象解析工具
    delete  m_panelBill;         // 信息显示
    delete m_parserThread;
}

//QString devAddr, QString devPort, QString localAddr, QString localPort
void NZ103Client::connectDevice(QString devAddr, QString devPort, QString localAddr, QString localPort)
{
    if ( Utils::checkIpFormat(devAddr) == false || Utils::checkIpFormat(localAddr) == false ) {
        qDebug() << m_errorList << "ip 地址格式错误！";
        return;
    }

    // 设置通信服务层的参数 本地服务器ip， 保护设备ip， 保护端口号1048，本地端口号1032
    m_server->setIPsandPorts(localAddr, devAddr, devPort, localPort);

    // 监听所有保护设备的ip地址， ip 地址是保护设备上设置的，端口号主站本机的1048
    if (m_server->tcpListen())
    {
        qDebug() << "开启 tcp 监听成功.";
        connect(m_server, &NZConnection::sig_newTcpConnection, this, &NZ103Client::slot_newConnected);    // 新的连接进入服务器
    }
    else {
        m_errorList.append("开启 tcp 监听失败!");
    }

    QString testUDP = "0";
    m_server->sendUdpMsg(testUDP);  // 发送一个udp 报文给保护，通知保护来连接我
}

void NZ103Client::readDeviceAll()
{
    slot_pushButtonReadAll_clicked();
    m_timerGetParseResult.start(TIME_GETDATA_NZ);
}

void NZ103Client::showTable()
{
    if (m_panelBill->checkTableDataSets()) {
        m_panelBill->show();
    }

    qDebug() << "最后结果 = " << m_tablesInfo.count();
    foreach ( BillTableStruct  it, m_tablesInfo ) {
        qDebug() << "SZNR103Parser 组号 =  " << it.groupNo << "结果 = "<< it.billRealValueList;
    }
}

void NZ103Client::getAllBillInfo(QMap<QString, BillTableStruct> &tablesInfo)
{
    // todo
    tablesInfo = m_tablesInfo;
}

void NZ103Client::disConnectDevice()
{
    m_server->stopTcpServer();
}

void NZ103Client::setBillGroup(QStringList &)
{

}

QStringList NZ103Client::getErrorLog()
{
    return m_errorList;
}


//发送广播： 1.广播服务端的地址出去，设备自动接收后连接主站
void NZ103Client::slot_pushButtonSendUdpMsg_clicked()
{
    QString msg = ui->lineEditUdpSend->text();
    m_server->sendUdpMsg(msg);
}

void NZ103Client::slot_UdpSocketRecv(QByteArray msg, QString ip, QString port)
{
    // 刷新到界面
    ui->textEditTcpRecv->append("[UDP 接收" + ip + port + " 消息]: " + msg );
}

void NZ103Client::on_pushButtonClearRecv_clicked()
{
    ui->textEditTcpRecv->clear();
}

void NZ103Client::sendCmdToDevice(const QString cmd)
{
    return  m_server->sendTcpMsg(cmd);
}

// 通过tcp socket接收
QString NZ103Client::getReplyFromDevice()
{
    return m_server->getDataFromTcpClient();
}

void NZ103Client::readBillArea()
{
    ui->textEditTcpRecv->append(" ******** 第 2 步 , 开始读取定值区号 ********");
    // 先确认选择当前组定值区号， 系统组00h ，条目 02h
    QString cpuAddr = ASDU_CPU_ADDR;
    ASDUStruct asduGetAreaCmd = m_constructer->constructGetBillArea(cpuAddr);
    m_server->sendTcpMsg(m_constructer->asduToQByteArray(asduGetAreaCmd));
}

// tcp 服务器向客户端发送消息
void NZ103Client::slot_pushButtonSendTcpMsg_clicked()
{
    // 当界面操作的阿时候设置参数
    if (ui->comboBoxConnections->currentIndex() == 0)
    {
        QString msg = ui->lineEditTcpSend->text();
        QString msgStr = msg.remove(" ").toUpper();
        // QByteArray msgByt = msgStr.toLatin1();

        // 从一个普通字符串转换为16进制字符
        // QByteArray bdata(QByteArray::fromHex(msg.toLatin1().toHex()));
        m_server->sendTcpMsg(msgStr);
    }
}

// 启动tcp服务器
void NZ103Client::slot_pushButtonStartTcpServer_clicked()
{
    // 设置 通信参数
    m_server->setIPsandPorts(ui->comboBoxLocalAddr->currentText(), ui->lineEditTargetAddr->text(), ui->lineEditTargetPort->text(), ui->lineEditLocalPort->text());
    qDebug() << "设置通信参数完毕。" << "设备ip：" <<ui->lineEditTargetAddr->text() << "port:" << ui->lineEditTargetPort->text();

    // 监听所有保护设备的ip地址， ip 地址是保护设备上设置的，端口号主站本机的1048
    if (m_server->tcpListen())
    {
        qDebug() << "开启 tcp 监听成功。";
        connect(m_server, &NZConnection::sig_newTcpConnection, this, &NZ103Client::slot_newConnected);    // 新的连接进入服务器
        ui->pushButtonSendUdpMsg->setEnabled(true);
    }
    QString testUDP = "00";
    m_server->sendUdpMsg(testUDP);
}

void NZ103Client::slot_pushButtonStopTcpServer_clicked()
{
    m_server->stopTcpServer();
    // 调用 Server 的停止服务接口
    ui->pushButtonStartTcpServer->setEnabled(true);
    ui->pushButtonStopTcpServer->setEnabled(false);
    ui->comboBoxConnections->clear();
    ui->pushButtonSendCMD->setEnabled(false);
    ui->pushButtonSendUdpMsg->setEnabled(false);
}

// 新的tcp连接与服务端建立
void NZ103Client::slot_newConnected(QString str)
{
    qDebug() << "新的连接接入";
    ui->pushButtonSendTcpMsg->setEnabled(true);
    ui->pushButtonStopTcpServer->setEnabled(true);
    ui->pushButtonReadAll->setEnabled(true);
    ui->pushButtonSendCMD->setEnabled(true);

    m_connectionInfo = m_server->getConnectedInfo();
    connect(m_server, &NZConnection::sig_readyReadTcp, this, &NZ103Client::slot_readTcpData);

    // 使用 Server 封装
    // 将连接到tcp服务端的设备ip显示在界面
    //    qDebug() << "NZ103Client 中获取连接状态信息：" <<  m_server->m_tcpServerSocket->ConnectedState;
    ui->comboBoxConnections->addItem(m_connectionInfo);
    ui->textEditTcpRecv->append(str);

    // 当有连接的时候就绑定新消息信号和新消息解析槽函数
    //    connect(this,SIGNAL(sig_newsRecv(QString)),this,SLOT(slot_newsParse(QString)));
    connect(this, &NZ103Client::sig_newsRecv, this, &NZ103Client::slot_newsParse);    // 改为多线程方式
}

void NZ103Client::slot_readData()
{
    QByteArray replyPacket = m_server->getDataFromTcp();

    qDebug() << "读取所有数据： " << replyPacket;
    //测试解析最后接收到的一条

    //ui->textEditTcpRecv->append("[" + m_connectionInfo+ "接收]" +"\n" + replyPacket);

    emit sig_newsRecv(replyPacket);     // 提示有新的消息接收到
}

void NZ103Client::slot_readTcpData(QByteArray packet)
{
    // 收到数据将数据存入缓存，等待解析展示
    m_recvList.append(packet);

    qDebug() << "开始进入接收报文的处理, 主线程 id = " << QThread::currentThreadId();
    emit sig_newsRecv(packet.toHex().toUpper());

    // 刷新界面
    ui->textEditTcpRecv->append("[tcp 接收]: " + packet.toHex().toUpper());
}

void NZ103Client::slot_tcpDisconnect()
{
    //    emit disconnected(m_tcpServerSocket->socketDescriptor());

    delete m_server;
}

void NZ103Client::slot_pushButtonClearTcpRecv_clicked()
{
    ui->textEditTcpRecv->clear();
}

void NZ103Client::slot_pushButtonSendCMD_clicked()
{
    // 使用 Server
    //qDebug() << " server 当前是否存在客户端连接： " << m_server->m_tcpServerSocket->state();
    // 从一个普通字符串转换为16进制字符
    QString msg = ui->comboBoxTcpCMD->currentText();
    QStringList msgList =  msg.split("]");
    msg = msgList.at(1);
    m_server->sendTcpMsg(msg);
}

void NZ103Client::slot_pushButtonShowTable_clicked()
{
    // 获取所有定值的名
    if(m_panelBill == nullptr)
    {
        m_panelBill = new PanelBill;

    }
    m_panelBill->show();
//    if( m_panelBill->checkTableDataSets() ){
//        m_panelBill->show();
//    }
//    else {
//        QMessageBox::information(this, "错误", "读取未完成!");
//    }
}

void NZ103Client::slot_updateBillNames()
{
    // 发送获取定值名字命令给设备，请求数据
    ASDUStruct packet =  m_constructer->constructGetBillValueNames("01", "03");
    packet.m_rii = Utils::uintStrToHexStr(m_rii, 2);
    qDebug() << "更新名字发送: "  << m_constructer->asduToQString(packet);
    sendCmdToDevice( m_constructer->asduToQString(packet) );
}

void NZ103Client::slot_newsParse(QByteArray packet)
{
    qDebug() << "开始进入接收报文的处理";
    // 判断是不是读所有定值名字

    // 1.判断返回报文的服务类型
    int type = m_parser->recvPacketTypeFilter(packet);

    // 读取定值区收到回复
    if (type == REPLY_READ_SETTINGS_AREA)
    {
        QStringList result = m_parser->parseBillInfo(type, packet);
        // m_currentBillArea = result.first();
        if ( false == result.isEmpty() ){
            ui->textEditTcpRecv->append(" *********** 当前定值区 = " + result.first() + " *********** ");
            emit sig_getBillAreaFinished(result.first());         // 通知已经收到读定值区号的响应， 下一步进行定值区的选择确认
            emit signal_parseFinished(result, type);
        }
    }

    if ( type == REPLY_READ_SURE_AREA ) {
        emit sig_sureBillAreaFinished();
    }

    if (type == REPLY_TYPE_ALL_GROUP_TITLE)                  // 确认是读标题的回应
    {
        if ( m_parser->getGroupNoWithName().count() != 0 )
        {
            ui->textEditTcpRecv->append("[本机消息]: 成共解析出标题信息。");
            //标题读完后可以读取定值区号信息
            emit sig_getTitleInfoFinished();
        }
    }

    qDebug() << "结束接收报文的分类处理 type = " <<type;

    // 2. 确认是否收到有用的消息回复
    if( type > -1 )
    {
        // 进行解析
        qDebug() << "对接收到的消息进行解析处理结果： " ;
        QStringList result = m_parser->parseBillInfo(type, packet);
        qDebug() << "parse 结果类型 :  " << type << result;
        // 3. 通知 table，是有用消息更新到table中
        emit signal_parseFinished(result, type);
        qDebug() << "结束接收报文的处理";
    }
}

void NZ103Client::slot_pushButtonGetModifiedValues_clicked()
{
    qDebug() << "新修改的值： " << m_panelBill->slot_getModifiedBillValues();
}

void NZ103Client::slot_updateUiAsSend(QString msg)
{
    ui->textEditTcpRecv->append(msg);
}

void NZ103Client::slot_readAllTitles()
{
    if (m_readTitleLimtCount == 0)
    {
        ui->textEditTcpRecv->append("[警告] 读取全部组标题信息超时！");
        m_readTitleTimer.stop();
        m_readTitleLimtCount = 10;
        return;
    }

    QString cpuAddr = ASDU_CPU_ADDR;
    ASDUStruct asduTitlesRead = m_constructer->constructReadAllTitles(cpuAddr);
    m_server->sendTcpMsg(m_constructer->asduToQByteArray(asduTitlesRead));
    --m_readTitleLimtCount;
}

void NZ103Client::selectBillArea(QString billArea)
{
    //0A 81 28 01 FE FA 77 01 00 02 01 03 01 01 00
    //0A 81 2A 01 FEFA7701000201030101
    QString cpuAddr = ASDU_CPU_ADDR;
    // 选取当前定值区号
    QString sysGroup = "00";
    QString ginNo = "02";
    ASDUStruct asduSelectAreaCmd = m_constructer->constructSelectArea(cpuAddr, sysGroup, ginNo, billArea);
    m_server->sendTcpMsg(m_constructer->asduToQByteArray(asduSelectAreaCmd));
   // qDebug() << "发送 tcp 消息选择当前定值区号  ： " << m_constructer->asduToQString(asduSelectAreaCmd);
}

void NZ103Client::readBillInfoes()
{
    QMap<QString,QString> groupNoWithNameMap =  m_parser->getGroupNoWithName();

    // 从全部组中获取有用的组信息,t同时对存放定值组信息的空间进行分配
    QString keyWords = SETTING_GROUP_NAME;
    QMap<QString,QString> billGroupInfo =  m_parser->getAboutBillGroupInfo(keyWords);

    qDebug() <<"***** 相关组有 ***" << billGroupInfo.keys() << billGroupInfo.values();

    // 发送读取定值组名称消息
    QStringList dataList = {KOD_DESCRIPTER, KOD_REAL_VALUE, KOD_DEFAULT_VALU, KOD_DIMENSION, KOD_UNIT };

    QByteArrayList cmdList;
    QString cpuAddr = ui->lineEditCpuAddr->text();

    foreach ( QString groupNo, billGroupInfo.keys())
    {
        if (groupNo.count() != 2)
        {
            groupNo = "0" + groupNo;
        }

        foreach( QString it, dataList )
        {
            ASDUStruct asdu = m_constructer->constructGetBillValueData(cpuAddr, groupNo, it);
            cmdList.append( m_constructer->asduToQByteArray(asdu) );
        }
    }

    m_server->sendTcpMsg(cmdList);
}

void NZ103Client::slot_setCanReadBillInfo()
{
    ui->textEditTcpRecv->append("[信息]: 成功完成读取标题信息任务。");
    m_readTitleTimer.stop();
    m_readTitleLimtCount = 10;

    ui->textEditTcpRecv->append( "****** 第 1 步，完成全部组标题读取********");
    //    m_canReadBillInfo = true;
    readBillArea();
}

void NZ103Client::slot_selectBillArea(QString billArea)
{
    ui->textEditTcpRecv->append("******第 3 步： 开始选择当前定值区号 ******");
    selectBillArea(billArea);
}

void NZ103Client::slot_readBillGroupInfo()
{
    // 确认定值区号得到回复后进行读取具体定值组信息
    readBillInfoes();
}

void NZ103Client::slot_getBillInfo()
{
    m_tablesInfo = m_parser->getBillTableInfo();
}


void NZ103Client::slot_pushButtonReadAll_clicked()
{
    // 1. 读定值区号

    // 2. 选择当前值区号

    // 3. 启动读标题定时器, 读全部组的标题
    m_readTitleLimtCount = 10;
    m_readTitleTimer.start(100);

    // 4.读取定值信息
}
